package cn.elwy.rcp.ui.widget;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TypedListener;

import cn.elwy.common.util.AssertUtil;
import cn.elwy.rcp.ui.util.ColorUtil;

/**
 * 自定义按钮类
 * @author huangsq
 * @version 1.0, 2013-11-20
 * @since 1.0, 2013-11-20
 */
public class CButton extends Canvas {

  /** 背景图像平铺 */
  public static int BG_IMAGE_TILE = 0;
  /** 背景图像拉伸 */
  public static int BG_IMAGE_STRETCH = 1;
  /** 背景图像居中 */
  public static int BG_IMAGE_CENTER = 2;
  public static int BG_IMAGE_CROP = 3;
  /** 按钮大小由背景图像决定，图像采用 */
  public static int BG_IMAGE_FIT = 4;
  public static int IMAGE_LEFT = 0;
  public static int IMAGE_RIGHT = 1;

  private boolean isInvalid = false;
  private boolean isNoBorder;
  private boolean isSelected;

  protected Image currentImage, currentBgImage;
  protected Image image, hotImage, pressedImage, disabledImage, selectedImage;// , backgroundImage;
  protected Image bgImage, bgHotImage, bgPressedImage, bgDisabledImage, bgSelectedImage;
  protected String text;
  protected Font font;
  protected Color fontColor, hoverFontColor, pressedFontColor, inactiveFontColor, selectedFontColor;
  protected Color borderColor, hoverBorderColor, pressedBorderColor, inactiveBorderColor, selectedBorderColor;
  protected Color currentFgColor, currentBgColor, currentFontColor, currentBorderColor;
  protected Color foregroundColor, backgroundColor;
  protected Color pressedFgColor, pressedBgColor;
  protected Color hoverFgColor, hoverBgColor;
  protected Color inactiveFgColor, inactiveBgColor;
  protected Color selectedFgColor, selecteBgdColor;
  protected int innerMarginWidth = 8;
  protected int innerMarginHeight = 5;
  protected int borderWidth = 1;
  protected int imagePadding = 5;
  protected boolean enabled = true;
  protected boolean roundedCorners = true;
  protected boolean isFocused = false;
  protected boolean selectionBorder = false;
  private int lastWidth, lastHeight;
  protected int backgroundImageStyle = BG_IMAGE_TILE;
  protected int imageStyle = 0;

  private DisposeListener disposeListener;
  private PaintListener paintListener;
  private Listener mouseEnterListener;
  private Listener focusOutListener;
  private Listener mouseExitListener;
  private Listener mouseUpListener;
  // private Listener mouseHoverListener;
  private Listener mouseDownListener;
  private Listener traverseListener;
  private Listener focusInListener;
  private Listener keyListener;

  public CButton(Composite parent) {
    super(parent, SWT.BORDER);
  }

  public CButton(Composite parent, int style) {
    super(parent, (style & ~SWT.BORDER) | SWT.NO_BACKGROUND);

    if ((style & SWT.BORDER) != SWT.BORDER) {
      isNoBorder = true;
    }
    if ((style & SWT.ICON) == SWT.ICON) {
      setMargin(0);
    }

    setBackgroundMode(SWT.INHERIT_DEFAULT);
    // 设置默认颜色 |
    setDefaultColors();
    // 初始化监听
    initListener();
    // 添加监听事件
    addListeners();
  }

  /**
   * 设置默认颜色
   */
  protected void setDefaultColors() {
    fontColor = ColorUtil.getColor(0, 0, 0);
    hoverFontColor = ColorUtil.getColor(0, 0, 0);
    pressedFontColor = ColorUtil.getColor(255, 255, 255);
    inactiveFontColor = ColorUtil.getColor(187, 187, 187);
    selectedFontColor = ColorUtil.getColor(160, 107, 38);
    borderColor = ColorUtil.getColor(187, 187, 187);
    hoverBorderColor = ColorUtil.getColor(147, 147, 147);
    pressedBorderColor = ColorUtil.getColor(147, 147, 147);
    inactiveBorderColor = ColorUtil.getColor(200, 200, 200);
    selectedBorderColor = ColorUtil.getColor(160, 107, 38);
    foregroundColor = ColorUtil.getColor(248, 248, 248);
    backgroundColor = ColorUtil.getColor(228, 228, 228);
    pressedFgColor = ColorUtil.getColor(120, 120, 120);
    pressedBgColor = ColorUtil.getColor(150, 150, 150);
    hoverFgColor = ColorUtil.getColor(248, 248, 248);
    hoverBgColor = ColorUtil.getColor(228, 228, 228);
    inactiveFgColor = ColorUtil.getColor(248, 248, 248);
    inactiveBgColor = ColorUtil.getColor(228, 228, 228);
    selectedFgColor = ColorUtil.getColor(238, 238, 238);
    selecteBgdColor = ColorUtil.getColor(218, 218, 218);
  }

  protected void addListeners() {
    addDisposeListener(disposeListener);
    addPaintListener(paintListener);
    addListener(SWT.MouseUp, mouseUpListener);
    addListener(SWT.MouseDown, mouseDownListener);
    addListener(SWT.MouseEnter, mouseEnterListener);
    addListener(SWT.MouseExit, mouseExitListener);
    // addListener(SWT.MouseHover, mouseHoverListener);
    // TAB TRAVERSAL (a KeyDown listener is also required)
    addListener(SWT.Traverse, traverseListener);
    addListener(SWT.FocusIn, focusInListener);
    addListener(SWT.FocusOut, focusOutListener);
    setTraversable(true);
  }

  protected void initListener() {

    disposeListener = new DisposeListener() {
      @Override
      public void widgetDisposed(DisposeEvent e) {
        // TODO clean up here (listeners?)
      }
    };

    paintListener = new PaintListener() {
      @Override
      public void paintControl(PaintEvent e) {
        if (currentFgColor == null) {
          currentFgColor = foregroundColor;
          currentBgColor = backgroundColor;
          currentBorderColor = borderColor;
          currentFontColor = fontColor;
        }

        // 设置画笔样式
        GC gc = e.gc;
        gc.setAntialias(SWT.ON);
        gc.setAdvanced(true);

        // 获取按钮大小
        Rectangle rect = getClientArea();

        // 设置背景颜色和父窗口一样，并且填充背景
        gc.setBackground(getParent().getBackground());
        gc.fillRectangle(rect);

        // 设置背景和前景颜色
        gc.setForeground(currentFgColor);
        gc.setBackground(currentBgColor);

        // 设置背景区域大小
        Rectangle fill = new Rectangle(rect.x, rect.y, rect.width, rect.height);
        int arcWidth = 0;
        int arcHeight = 0;
        int bw = borderWidth;
        if (!isNoBorder) {
          if (bw < 1) {
            bw = 1;
          }
          if (roundedCorners) {
            arcWidth = Math.max(5, (rect.y / 10));
            arcHeight = arcWidth;
            fill.x = rect.x + bw;
            fill.y = rect.y + bw;
            fill.width = rect.width - 2 * bw;
            fill.height = rect.height - 2 * bw;
          } else {
            if (bw > 1) {
              fill.x = rect.x + bw;
              fill.y = rect.y + bw;
              fill.width = rect.width - 2 * bw;
              fill.height = rect.height - 2 * bw;
            } else {
              fill.width = rect.width - bw;
              fill.height = rect.height - bw;
            }
          }
        } else {
          bw = 0;
        }
        // 填充背景区域
        gc.fillRoundRectangle(fill.x, fill.y, fill.width, fill.height, arcWidth, arcHeight);

        // 画背景图片

        drawBackgroundImage(gc, fill);

        int x = innerMarginWidth + bw;
        int y = innerMarginHeight + bw;
        if (imageStyle == IMAGE_RIGHT) {
          if (!AssertUtil.isEmpty(text)) {
            drawText(gc, x, y);
          }
          if (currentImage != null) {
            x = rect.width - x - currentImage.getBounds().width + imagePadding;
            drawImage(gc, x, y);
          }
        } else {
          x = drawImage(gc, x, y);
          if (!AssertUtil.isEmpty(text)) {
            drawText(gc, x, y);
          }
        }

        if (!isNoBorder) {// 如果按钮有边框
          // 设置边框大小及样式
          gc.setLineWidth(bw);
          gc.setLineStyle(SWT.LINE_SOLID);
          gc.setForeground(currentBorderColor);

          // 如果设置了选中时设置边框
          if (isFocused && selectionBorder) {
            gc.setLineStyle(SWT.LINE_DASH);
            gc.setForeground(currentFontColor);
          }
          if (roundedCorners) {
            gc.drawRoundRectangle(fill.x, fill.y, fill.width, fill.height, arcWidth, arcHeight);
          } else {
            // 画矩形边框
            gc.drawRectangle(fill.x, fill.y, fill.width, fill.height);
          }
        }

      }

    };

    // 鼠标进入按钮事件
    mouseEnterListener = new Listener() {
      @Override
      public void handleEvent(Event e) {
        isInvalid = false;
        setHoverStyle(e);
      }
    };

    // 鼠标离开按钮事件
    mouseExitListener = new Listener() {
      @Override
      public void handleEvent(Event e) {
        isInvalid = true;
        // 如果聚焦或选中状态
        if (isFocused || isSelected) {
          setSelectedStyle(e);
        } else {
          setNormalStyle(e);
        }
      }
    };

    mouseUpListener = new Listener() {
      @Override
      public void handleEvent(Event e) {
        if (isInvalid) { // 如果鼠标不在按钮上
          if (isFocused || isSelected) {
            setSelectedStyle(e);
          } else {
            setNormalStyle(e);
          }
        } else if (e.button == 1) {
          setHoverStyle(e);
          if ((e.count == 1) && enabled && (getClientArea().contains(e.x, e.y))) {
            notifySelectionListener();
          }
        }
      }
    };

    mouseDownListener = new Listener() {
      @Override
      public void handleEvent(Event e) {
        if (e.button == 1) {
          setPressedStyle(e);
        }
      }
    };

    traverseListener = new Listener() {
      @Override
      public void handleEvent(Event e) {
        switch (e.detail) {
          case SWT.TRAVERSE_ESCAPE:
          case SWT.TRAVERSE_RETURN:
          case SWT.TRAVERSE_TAB_NEXT:
          case SWT.TRAVERSE_TAB_PREVIOUS:
          case SWT.TRAVERSE_PAGE_NEXT:
          case SWT.TRAVERSE_PAGE_PREVIOUS:
            e.doit = true;
            break;
        }
      }
    };

    focusInListener = new Listener() {
      @Override
      public void handleEvent(Event e) {
        isFocused = true;
        setSelectedStyle(e);
      }
    };

    focusOutListener = new Listener() {
      @Override
      public void handleEvent(Event e) {
        isFocused = false;
        setNormalStyle(e);
      }
    };

    keyListener = new Listener() {
      boolean keyDown = true;

      @Override
      public void handleEvent(Event e) {
        switch (e.type) {
          case SWT.KeyDown:
            keyDown(e);
            break;
          case SWT.KeyUp:
            keyUp(e);
            break;
        }
      }

      protected void keyDown(Event e) {
        if (!keyDown) {
          return;
        }
        keyDown = false;
        if (isKeyPress(e)) {
          setPressedStyle(e);
          // redraw();
          notifySelectionListener();
        }
      }

      private void keyUp(Event e) {
        keyDown = true;
        if (isKeyPress(e)) {
          isFocused = true;
          setSelectedStyle(e);
          // redraw();
        }
      }

      private boolean isKeyPress(Event e) {
        char character = e.character;
        return character == ' ' || character == '\r' || character == '\n';
        // int keyCode = e.keyCode;
        // return keyCode == SWT.SPACE || keyCode == SWT.CR;
      }

    };

  }

  /**
   * SelectionListeners are notified when the button is clicked
   * @param listener
   */
  public void addSelectionListener(SelectionListener listener) {
    addListener(SWT.Selection, new TypedListener(listener));
  }

  public void removeSelectionListener(SelectionListener listener) {
    removeListener(SWT.Selection, listener);
  }

  protected void setTraversable(boolean canTraverse) {
    if (canTraverse) {
      addListener(SWT.KeyUp, keyListener);
      addListener(SWT.KeyDown, keyListener);
    } else {
      removeListener(SWT.KeyUp, keyListener);
      removeListener(SWT.KeyDown, keyListener);
    }
  }

  /**
   * 通知选择事件
   */
  protected void notifySelectionListener() {
    Event e = new Event();
    e.item = this;
    e.widget = this;
    e.type = SWT.Selection;
    notifyListeners(SWT.Selection, e);
  }

  /**
   * 设置默认样式
   * @param e
   */
  protected void setNormalStyle(Event e) {
    setEventImage(image);
    setEventBgImage(bgImage);
    setEventColor(foregroundColor, backgroundColor, borderColor, fontColor);
  }

  /**
   * 设置鼠标悬停样式
   * @param e
   */
  protected void setHoverStyle(Event e) {
    setEventImage(hotImage);
    setEventBgImage(bgHotImage);
    setEventColor(hoverFgColor, hoverBgColor, hoverBorderColor, hoverFontColor);
  }

  /**
   * 设置按钮按下样式
   * @param e
   */
  protected void setPressedStyle(Event e) {
    setEventImage(pressedImage);
    setEventBgImage(bgPressedImage);
    setEventColor(pressedFgColor, pressedBgColor, pressedBorderColor, pressedFontColor);
  }

  /**
   * 设置按钮禁用样式
   * @param e
   */
  protected void setInactiveStyle(Event e) {
    setEventImage(disabledImage);
    setEventBgImage(bgDisabledImage);
    setEventColor(inactiveFgColor, inactiveBgColor, inactiveBorderColor, inactiveFontColor);
  }

  /**
   * 设置选中样式
   * @param e
   */
  protected void setSelectedStyle(Event e) {
    setEventImage(selectedImage);
    setEventBgImage(bgSelectedImage);
    setEventColor(selectedFgColor, selecteBgdColor, selectedBorderColor, selectedFontColor);
  }

  /**
   * 设置触发按钮事件的颜色
   */
  protected void setEventColor(Color fgColor, Color bgColor, Color bdrColor, Color fntColor) {
    if (!this.enabled) {
      return;
    }

    if (currentFgColor == null) {
      currentFgColor = foregroundColor;
      currentBgColor = backgroundColor;
      currentBorderColor = borderColor;
      currentFontColor = fontColor;
    }

    boolean redrawFlag = false;
    if ((fgColor != null) && (!currentFgColor.equals(fgColor))) {
      currentFgColor = currentBgColor = fgColor;
      if (bgColor != null) {
        currentBgColor = bgColor;
      }
      redrawFlag = true;
    }
    if ((bdrColor != null) && (!currentBorderColor.equals(bdrColor))) {
      currentBorderColor = bdrColor;
      redrawFlag = true;
    }
    if ((fntColor != null) && (!currentFontColor.equals(fntColor))) {
      currentFontColor = fntColor;
      redrawFlag = true;
    }
    if (redrawFlag) {
      redraw();
    }
  }

  /**
   * 设置触发按钮事件时图像
   */
  protected void setEventImage(Image image) {
    if (!this.enabled) {
      return;
    }
    if (image != null) {
      currentImage = image;
    }
  }

  /**
   * 设置触发按钮事件时背景图像
   */
  protected void setEventBgImage(Image gbImage) {
    if (!this.enabled) {
      return;
    }
    if (gbImage != null) {
      currentBgImage = gbImage;
    }
  }

  private void drawText(GC gc, int x, int y) {
    gc.setFont(font);
    gc.setForeground(currentFontColor);
    gc.drawText(text, x, y, SWT.DRAW_TRANSPARENT);
  }

  private int drawImage(GC gc, int x, int y) {
    if (currentImage == null)
      return x;
    gc.drawImage(currentImage, x, y);
    return x + currentImage.getBounds().width + imagePadding;
  }

  private void drawBackgroundImage(GC gc, Rectangle rect) {
    if (currentBgImage == null)
      return;

    Rectangle imgBounds = currentBgImage.getBounds();

    if (backgroundImageStyle == BG_IMAGE_TILE) {
      Rectangle tileRect = new Rectangle(rect.x, rect.y, rect.width, rect.height);
      for (int y = 0; y < rect.height; y = y + imgBounds.height) {
        for (int x = 0; x < rect.width; x = x + imgBounds.width) {
          drawClippedImage(gc, currentBgImage, 0, 0, tileRect);
          tileRect.x += imgBounds.width;
          tileRect.width -= imgBounds.width;
        }
        tileRect.x = rect.x;
        tileRect.width = rect.width;
        tileRect.height = rect.height;
        tileRect.y += imgBounds.height;
        tileRect.height -= imgBounds.height;
      }
    } else if (backgroundImageStyle == BG_IMAGE_STRETCH) {
      gc.drawImage(currentBgImage, 0, 0, imgBounds.width, imgBounds.height, rect.x, rect.y, rect.width, rect.height);
    } else if (backgroundImageStyle == BG_IMAGE_CENTER) {
      int x = (imgBounds.width - rect.width) / 2;
      int y = (imgBounds.height - rect.height) / 2;
      Rectangle centerRect = new Rectangle(rect.x, rect.y, rect.width, rect.height);
      if (x < 0) {
        centerRect.x -= x;
        x = 0;
      }
      if (y < 0) {
        centerRect.y -= y;
        y = 0;
      }
      drawClippedImage(gc, currentBgImage, x, y, centerRect);
    } else { // BG_IMAGE_CROP,BG_IMAGE_FIT
      drawClippedImage(gc, currentBgImage, 0, 0, rect);
    }
  }

  private int drawClippedImage(GC gc, Image image, int x, int y, Rectangle rect) {
    if (image != null) {
      Rectangle imgBounds = image.getBounds();
      int width = Math.min(imgBounds.width - x, rect.width);
      int height = Math.min(imgBounds.height - y, rect.height);
      gc.drawImage(image, x, y, width, height, rect.x, rect.y, width, height);
      return width;
    }
    return 0;
  }

  @Override
  public Point computeSize(int wHint, int hHint, boolean changed) {
    if ((wHint == SWT.DEFAULT) && (hHint == SWT.DEFAULT) && !changed && (lastWidth > 0) && (lastHeight > 0)) {
      return new Point(lastWidth, lastHeight);
    }

    int width = 0, height = 0;
    if (currentImage != null) {
      Rectangle bounds = currentImage.getBounds();
      width += bounds.width + imagePadding;
      height += bounds.height + (this.innerMarginHeight * 2);
    }
    if (text != null) {
      GC gc = new GC(this);
      gc.setFont(font);
      // Point extent = gc.stringExtent(data); // stringExtent ignores linefeeds
      Point extent = gc.textExtent(text);
      gc.dispose();

      width += extent.x + (this.innerMarginWidth * 2);
      height = Math.max(height, extent.y + (this.innerMarginHeight * 2));
    }
    // height += 2 * this.innerMarginHeight;
    // width += 2 * this.innerMarginWidth;

    if ((currentBgImage != null) && (backgroundImageStyle == BG_IMAGE_FIT)) {
      width = currentBgImage.getBounds().width;
      height = currentBgImage.getBounds().height;
    }
    if (!isNoBorder) {
      width += 2 * borderWidth;
      height += 2 * borderWidth;
    }

    if (wHint != SWT.DEFAULT) {
      width = wHint;
    }
    if (hHint != SWT.DEFAULT) {
      height = hHint;
    }

    lastWidth = width;
    lastHeight = height;
    return new Point(lastWidth, lastHeight);
  }

  /**
   * 设置按钮图像
   * @param image 默认图像
   * @param hotImage 鼠标悬停图像
   * @param pressedImage 按钮按下图像
   * @param disabledImage 按钮禁用图像
   * @param selectedImage 按钮选择中图像，用于一组按钮单选的功能
   */
  public void setImages(Image image, Image hotImage, Image pressedImage, Image disabledImage, Image selectedImage) {
    setImage(image);

    if (hotImage != null) {
      this.hotImage = hotImage;
    }
    if (pressedImage != null) {
      this.pressedImage = pressedImage;
    }
    if (disabledImage != null) {
      this.disabledImage = disabledImage;
    }
    if (selectedImage != null) {
      this.selectedImage = selectedImage;
    }
  }

  /**
   * This is an image that will be displayed to the side of the data inside the button (if any). By default the image
   * will be to the left of the data; however, setImageStyle can be used to specify that it's either to the right or
   * left. If there is no data, the image will be centered inside the button.
   * @param image
   */
  public void setImage(Image image) {
    this.image = image;
    this.currentImage = image;
    redraw();
  }

  public Image getImage() {
    return image;
  }

  /**
   * Set the style with which the side image is drawn, either IMAGE_LEFT or IMAGE_RIGHT (default is IMAGE_LEFT).
   * @param imageStyle
   */
  public void setImageStyle(int imageStyle) {
    this.imageStyle = imageStyle;
  }

  public int getImageStyle() {
    return imageStyle;
  }

  /**
   * This is an image that will be used as a background image for the button, drawn in the manner specified by the
   * backgroundImageStyle setting. The order in which the button is drawn is: background color, then background image,
   * then button image and data. So if the background image has transparency, the background color will show through the
   * transparency.
   */
  @Override
  public void setBackgroundImage(Image backgroundImage) {
    this.bgImage = backgroundImage;
    currentBgImage = backgroundImage;
    // redraw();
    super.setBackgroundImage(backgroundImage);
  }

  /**
   * 设置按钮图像
   * @param bgImage 默认背景图像
   * @param bgHotImage 鼠标悬停背景图像
   * @param bgPressedImage 按钮按下背景图像
   * @param bgDisabledImage 按钮禁用背景图像
   * @param bgSelectedImage 按钮选择中背景图像，用于一组按钮单选的功能
   */
  public void setBgImages(Image bgImage, Image bgHotImage, Image bgPressedImage, Image bgDisabledImage,
      Image bgSelectedImage) {
    setBackgroundImage(bgImage);

    if (bgHotImage != null) {
      this.bgHotImage = bgHotImage;
    } else {
      this.bgHotImage = bgImage;
    }
    if (bgPressedImage != null) {
      this.bgPressedImage = bgPressedImage;
    } else {
      this.bgPressedImage = bgImage;
    }
    if (bgDisabledImage != null) {
      this.bgDisabledImage = bgDisabledImage;
    } else {
      this.bgDisabledImage = bgImage;
    }
    if (bgSelectedImage != null) {
      this.bgSelectedImage = bgSelectedImage;
    } else {
      this.bgSelectedImage = bgImage;
    }
  }

  @Override
  public Image getBackgroundImage() {
    return bgImage;
  }

  /**
   * Set the style with which the background image is drawn (default is BG_IMAGE_CROP). The different styles are:
   * <p>
   * <ul>
   * <li>BG_IMAGE_CROP: the image is drawn once, with the top left corner of the image at the top left corner of the
   * button. Any part of the image that is too wide or too tall to fit inside the button area is clipped (cropped) off.
   * </li>
   * <li>BG_IMAGE_STRETCH: the image is stretched (or squashed) to exactly fit the button area.</li>
   * <li>BG_IMAGE_TILE: the image is tiled vertically and horizontally to cover the entire button area.</li>
   * <li>BG_IMAGE_CENTER: the center of the image is placed inside the center of the button. Any part of the image that
   * is too tall or too wide to fit will be clipped.</li>
   * <li>BG_IMAGE_FIT: the button will be the exact size of the image. Note that this can sometimes truncate the data
   * inside the button.</li>
   * </ul>
   * @param backgroundImageStyle
   */
  public void setBackgroundImageStyle(int backgroundImageStyle) {
    this.backgroundImageStyle = backgroundImageStyle;
  }

  public int getBackgroundImageStyle() {
    return backgroundImageStyle;
  }

  public String getText() {
    return text;
  }

  public void setText(String text) {
    this.text = text;
    redraw();
  }

  @Override
  public Font getFont() {
    return font;
  }

  @Override
  public void setFont(Font font) {
    if (font != null) {
      this.font = font;
    }
  }

  /**
   * Set whether or not this button is enabled (active) or not (inactive). This setting can be changed dynamically after
   * the button has been drawn.
   * <p>
   * An inactive button does not change color when it is hovered over or clicked, does not receive focus or participate
   * in the tab order of the widget container, and does not notify listeners when clicked.
   */
  @Override
  public void setEnabled(boolean enabled) {
    if (this.enabled != enabled) {
      this.enabled = enabled;
      if (!enabled) {
        this.enabled = true;
        this.setInactiveStyle(null);
        this.setTraversable(false);
        this.enabled = false;
      } else {
        this.setNormalStyle(null);
        this.setTraversable(true);
      }
    }
  }

  @Override
  public boolean getEnabled() {
    return enabled;
  }

  @Override
  public boolean isEnabled() {
    return enabled;
  }

  /**
   * Set the inner margin between the left and right of the data inside the button and the button borders, in pixels.
   * Like the left and right padding for the data. Default is 8 pixels.
   * @param innerMarginWidth
   */
  public void setInnerMarginWidth(int innerMarginWidth) {
    if (innerMarginWidth >= 0)
      this.innerMarginWidth = innerMarginWidth;
  }

  public int getInnerMarginWidth() {
    return innerMarginWidth;
  }

  /**
   * Set the inner margin between the top and bottom of the data inside the button and the button borders, in pixels.
   * Like the top and bottom padding for the data. Default is 4 pixels.
   * @param innerMarginHeight
   */
  public void setInnerMarginHeight(int innerMarginHeight) {
    if (innerMarginHeight >= 0)
      this.innerMarginHeight = innerMarginHeight;
  }

  public int getInnerMarginHeight() {
    return innerMarginHeight;
  }

  /**
   * 设置图像边距
   */
  public void setImagePadding(int imagePadding) {
    if (imagePadding >= 0)
      this.imagePadding = imagePadding;
  }

  public int getImagePadding() {
    return imagePadding;
  }

  /**
   * Set whether or not the button should have rounded corners (default is true).
   * @param roundedCorners
   */
  public void setRoundedCorners(boolean roundedCorners) {
    this.roundedCorners = roundedCorners;
  }

  public boolean hasRoundedCorners() {
    return roundedCorners;
  }

  /**
   * Set whether or not a dotted-line border should be drawn around the data inside the button when the button has tab
   * focus. Default is false (no selection border). If a selection border is used, it will be the same color as the font
   * color. Note that you can also use setSelectedColors() to change the look of the button when it has focus.
   * @param selectionBorder
   */
  public void setSelectionBorder(boolean selectionBorder) {
    this.selectionBorder = selectionBorder;
  }

  public boolean hasSelectionBorder() {
    return selectionBorder;
  }

  /**
   * Set the width of the button border, in pixels (default is 1).
   * @param borderWidth
   */
  public void setBorderWidth(int borderWidth) {
    this.borderWidth = borderWidth;
  }

  @Override
  public int getBorderWidth() {
    return borderWidth;
  }

  /**
   * 设置边距
   * @param margin
   */
  public void setMargin(int margin) {
    innerMarginHeight = margin;
    innerMarginWidth = margin;
    imagePadding = margin;
  }

  /**
   * The colors of the button in its "default" state (not clicked, selected, etc.)
   * @param fgColor the gradient color at the top of the button
   * @param bgColor the gradient color at the bottom of the button (if you don't want a gradient, set this to fgColor)
   * @param bdrColor the color of the border around the button (if you don't want a border, use getBackground())
   * @param fntColor the color of the font inside the button
   */
  public void setDefaultColors(Color fgColor, Color bgColor, Color bdrColor, Color fntColor) {
    if (fgColor != null) {
      this.foregroundColor = fgColor;
    }
    if (bgColor != null) {
      this.backgroundColor = bgColor;
    }
    if (bdrColor != null) {
      this.borderColor = bdrColor;
    }
    if (fntColor != null) {
      this.fontColor = fntColor;
    }
  }

  /**
   * The colors of the button when the mouse is hovering over it
   * @param fgColor the gradient color at the top of the button
   * @param bgColor the gradient color at the bottom of the button (if you don't want a gradient, set this to fgColor)
   * @param bdrColor the color of the border around the button (if you don't want a border, use getBackground())
   * @param fntColor the color of the font inside the button
   */
  public void setHoverColors(Color fgColor, Color bgColor, Color bdrColor, Color fntColor) {
    if (fgColor != null) {
      this.hoverFgColor = fgColor;
    }
    if (bgColor != null) {
      this.hoverBgColor = bgColor;
    }
    if (bdrColor != null) {
      this.hoverBorderColor = bdrColor;
    }
    if (fntColor != null) {
      this.hoverFontColor = fntColor;
    }
  }

  /**
   * The colors of the button when it is being clicked (MouseDown)
   * @param fgColor the gradient color at the top of the button
   * @param bgColor the gradient color at the bottom of the button (if you don't want a gradient, set this to fgColor)
   * @param bdrColor the color of the border around the button (if you don't want a border, use getBackground())
   * @param fntColor the color of the font inside the button
   */
  public void setPressedColors(Color fgColor, Color bgColor, Color bdrColor, Color fntColor) {
    if (fgColor != null) {
      this.pressedFgColor = fgColor;
    }
    if (bgColor != null) {
      this.pressedBgColor = bgColor;
    }
    if (bdrColor != null) {
      this.pressedBorderColor = bdrColor;
    }
    if (fntColor != null) {
      this.pressedFontColor = fntColor;
    }
  }

  /**
   * The colors of the button when it has focus
   * @param fgColor the gradient color at the top of the button
   * @param bgColor the gradient color at the bottom of the button (if you don't want a gradient, set this to fgColor)
   * @param bdrColor the color of the border around the button (if you don't want a border, use getBackground())
   * @param fntColor the color of the font inside the button
   */
  public void setSelectedColors(Color fgColor, Color bgColor, Color bdrColor, Color fntColor) {
    if (fgColor != null) {
      this.selectedFgColor = fgColor;
    }
    if (bgColor != null) {
      this.selecteBgdColor = bgColor;
    }
    if (bdrColor != null) {
      this.selectedBorderColor = bdrColor;
    }
    if (fntColor != null) {
      this.selectedFontColor = fntColor;
    }
  }

  /**
   * The colors of the button when it is in an inactive (not enabled) state
   * @param fgColor the gradient color at the top of the button
   * @param bgColor the gradient color at the bottom of the button (if you don't want a gradient, set this to fgColor)
   * @param bdrColor the color of the border around the button (if you don't want a border, use getBackground())
   * @param fntColor the color of the font inside the button
   */
  public void setInactiveColors(Color fgColor, Color bgColor, Color bdrColor, Color fntColor) {
    if (fgColor != null) {
      this.inactiveFgColor = fgColor;
    }
    if (bgColor != null) {
      this.inactiveBgColor = bgColor;
    }
    if (bdrColor != null) {
      this.inactiveBorderColor = bdrColor;
    }
    if (fntColor != null) {
      this.inactiveFontColor = fntColor;
    }
  }

}
